/**
 * &lt;p&gt;
 * copyright &amp;copy;  2015, all rights reserved.
 * @author Administrator
 * @version $Id$
 * @since 1.0
 * 
 */
package com.concurrents.volatiles;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 测试 volatile 
 * 2.volatile不能确保原子性 <p>
 * 
 * 在前面已经提到过，自增操作是不具备原子性的，它包括读取变量的原始值、进行加1操作、写入工作内存。那么就是说自增操作的三个子操作可能会分割开执行，就有可能导致下面这种情况出现：

假如某个时刻变量inc的值为10，

线程1对变量进行自增操作，线程1先读取了变量inc的原始值，然后线程1被阻塞了；

然后线程2对变量进行自增操作，线程2也去读取变量inc的原始值，由于线程1只是对变量inc进行读取操作，而没有对变量进行修改操作，所以不会导致线程2的工作内存中缓存变量inc的缓存行无效，也不会导致主存中的值刷新，所以线程2会直接去主存读取inc的值，发现inc的值时10，然后进行加1操作，并把11写入工作内存，最后写入主存。

然后线程1接着进行加1操作，由于已经读取了inc的值，注意此时在线程1的工作内存中inc的值仍然为10，所以线程1对inc进行加1操作后inc的值为11，然后将11写入工作内存，最后写入主存。

那么两个线程分别进行了一次自增操作后，inc只增加了1。

根源就在这里，自增操作不是原子性操作，而且volatile也无法保证对变量的任何操作都是原子性的。
 * @author LingMin 
 * @date 2017年4月7日<br>
 * @version 1.0<br>
 */
public class TestVolatile {
    //非原子性变量，需要结合 synchronized 或 Lock使用 达到效果
	public volatile int inc = 0;//volatile
	//原子性变量
	public AtomicInteger inc1 = new AtomicInteger(0);
	/***
	 * 该方法增加 同步synchronized 才能保证原子性，否则结构不正确 <p>
	 *  <p>
	 * void
	 */
    public void increase() {
        inc++;
        inc1.getAndIncrement();
    }
 
    public static void main(String[] args) {
        final TestVolatile test = new TestVolatile();
        for(int i=0;i<10;i++){
            new Thread(){
                public void run() {
                    for(int j=0;j<1000;j++)
                        test.increase();
                };
            }.start();
        }
 
        while(Thread.activeCount()>1)  //保证前面的线程都执行完
            Thread.yield();
        System.out.println("inc="+test.inc);
        System.out.println("AtomicInteger inc1="+test.inc1.get());
    }

}
